/*
 * Copyright (c) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { PluginExtension } from '../framework';
import { AnnotationAnalyzerRegistry } from './analyzer/AnnotationAnalyzerRegistry';
import { ConstantAnalyzer } from './analyzer/utils/ConstantAnalyzer';
import { HMRouterExtensionContext } from './HMRouterExtensionContext';
import {
  CodeGenerationProcessor,
  CompletionProcessor,
  ConfigUpdateProcessor,
  InitializerProcessor,
  ObfuscationProcessor,
  ResourceProcessProcessor,
  RouterMapBuildingProcessor,
} from './processor';
import { SourceFile } from 'ts-morph';
import { Logger } from '../framework';

export class HMRouterDefaultExtension extends PluginExtension<HMRouterExtensionContext> {
  get name(): string {
    return 'HMRouterExtension';
  }

  afterInitialize(context: HMRouterExtensionContext): void {
    const initializer = new InitializerProcessor(context);
    initializer.execute();
  }

  afterAnnotationAnalysis(sourceFile: SourceFile, filePath: string, context: HMRouterExtensionContext): void {
    if (context.moduleIgnored) {
      Logger.debug(this.name, 'module ignored: annotationAnalysis');
      return;
    }
    AnnotationAnalyzerRegistry.getInstance().initialize(context.config.modulePath);

    const analyzers = AnnotationAnalyzerRegistry.getInstance().getAnalyzers();
    for (const analyzer of analyzers) {
      analyzer.analyze(sourceFile, filePath, context);
    }

    // Execute constant parsing for current file results
    this.executeConstantParsing(filePath, context);
  }

  /**
   * Execute constant parsing for current file analysis results
   * @param filePath Current file path
   * @param context HMRouter extension context
   * @private
   */
  private executeConstantParsing(filePath: string, context: HMRouterExtensionContext): void {
    try {
      // Access private fields through type conversion
      const contextImpl = context as any;
      const analyzeResults = contextImpl.analyzeResults as Set<any>;
      const currentView = contextImpl._currentView as any[];
      const currentFilePath = contextImpl._currentFilePath as string;

      // Filter current file results from analyzeResults
      const currentFileResults: any[] = [];
      analyzeResults.forEach((result: any) => {
        if (result.sourceFilePath === currentFilePath) {
          currentFileResults.push(result);
        }
      });

      if (currentFileResults.length === 0) {
        return;
      }

      Logger.debug(this.name, `Start constant parsing for ${currentFileResults.length} results in file: ${filePath}`);

      // Get constant resolver and create analyzer
      const constantResolver = AnnotationAnalyzerRegistry.getInstance().getConstantResolver();
      if (!constantResolver) {
        Logger.warn(this.name, `Constant resolver not available, skip constant parsing for file: ${filePath}`);
        return;
      }

      const constantAnalyzer = new ConstantAnalyzer(constantResolver);

      // 创建当前文件结果的副本
      const currentFileResultsCopy = currentFileResults.map((result) => ({ ...result }));

      // 解析常量
      const resultsSet = new Set(currentFileResultsCopy);
      constantAnalyzer.parseConstants(resultsSet);

      // 更新 analyzeResults Set: 保持对象引用不变，只更新需要解析的属性值
      const updatedResults = new Set<any>();

      // 首先添加非当前文件的结果
      analyzeResults.forEach((result: any) => {
        if (result.sourceFilePath !== currentFilePath) {
          updatedResults.add(result);
        }
      });

      // 然后添加解析后的当前文件结果
      resultsSet.forEach((parsedResult: any) => {
        updatedResults.add(parsedResult);
      });

      // 最后，用更新后的结果替换原来的 analyzeResults
      contextImpl.analyzeResults = updatedResults;

      // 更新 currentView 数组
      for (let i = 0; i < currentView.length; i++) {
        this.getCurrentView(currentView, currentFilePath, resultsSet, i);
      }

      Logger.debug(this.name, `Constant parsing completed for file: ${filePath}`);
    } catch (error) {
      Logger.warn(this.name, `Failed to execute constant parsing for file ${filePath}: ${error}`);
    }
  }

  private getCurrentView(currentView: any[], currentFilePath: string, resultsSet: Set<any>, i: number): void {
    // 更新 currentView 数组
    const viewResult = currentView[i];
    if (viewResult.sourceFilePath === currentFilePath) {
      for (const parsedResult of resultsSet) {
        if (parsedResult.name === viewResult.name && parsedResult.sourceFilePath === viewResult.sourceFilePath) {
          currentView[i] = parsedResult;
          break;
        }
      }
    }
  }

  afterCodeGeneration(context: HMRouterExtensionContext): void {
    if (context.moduleIgnored) {
      Logger.debug(this.name, 'module ignored: codeGeneration');
      return;
    }
    const generator = new CodeGenerationProcessor(context);
    generator.execute();
  }

  afterRouterMapBuilding(context: HMRouterExtensionContext): void {
    const builder = new RouterMapBuildingProcessor(context);
    builder.execute();
  }

  afterConfigUpdate(context: HMRouterExtensionContext): void {
    const processor = new ConfigUpdateProcessor(context);
    processor.execute();
  }

  afterObfuscationProcess(context: HMRouterExtensionContext): void {
    if (context.moduleIgnored) {
      Logger.debug(this.name, 'module ignored: obfuscationProcess');
      return;
    }
    const processor = new ObfuscationProcessor(context);
    processor.execute();
  }

  afterResourceProcess(context: HMRouterExtensionContext): void {
    const processor = new ResourceProcessProcessor(context);
    processor.execute();
  }

  afterCompletion(context: HMRouterExtensionContext): void {
    const processor = new CompletionProcessor(context);
    processor.execute();
  }
}
